PS Jailbreak 原理分析 您所在的位置:网站首页 陆旸 社科院 PS Jailbreak 原理分析

PS Jailbreak 原理分析

2024-02-17 14:27| 来源: 网络整理| 查看: 265

很久没有写技术文章了,最近PS3破解比较火热,我就分析一下。

首先需要介绍一些破解用到的底层技术:

Heap overflow

Heap(堆)是所有编程语言底层内存管理的基础,即便用汇编可以胡乱搞,写大程序也肯定还会用到堆管理器。在cc++里面,当我们用malloc、free、new、delete之类的内存操作函数,我们就和堆管理器打交道了。堆管理器的实现有很多种,算法各有不同,有用红黑树,也有简单的linklist,还有为了提高性能只能分配固定尺寸的内存池。

这些不同的实现大多数有一个典型特征:对齐。由于现代计算机体系结构的缘故,对齐的数据才有较高的访问速度,在某些硬件体系架构上,访问非对齐内存甚至会直接导致machine check。由于对齐,比如我们请求100字节,其实堆管理器会自动选取一个对齐的尺寸,然后分配那么大的一块,比如说128字节,来返回给我们。当然这个描述是不精确的,下面解释一下。

堆管理器需要维护它所管理的每一块内存,也就是说,要维护每块内存的相关信息,比如长度,向前向后指针,状态(未分配,已分配等),那么这个状态怎么维护呢?一种很常见的做法是,放在这个内存块的首部。

假设现在程序员申请100字节,内存块信息本身16字节,那么堆管理器就会找一个128长度的内存块(如果没有这么大的,它会按照一定的算法,比如根据每块内存的信息合并未分配块),把这块内存的首指针+16返回给程序员,于是程序员很高兴,他有了100字节的内存。注意,在古老的系统上其实他可以安全的访问128-16字节。在现代系统上就不行了,堆管理器会在这100字节前后做特殊标记,在硬件页的尺度上也会设定一定的保护(请参考NXDEP),如果你写过了100,当free这块内存的时候,堆管理器会发现标记被破坏,也就是heap overflow了。

如果我们在这100字节的内存上写了256字节的数据呢?一个极大概率的事件是:我们破坏了邻近的内存块的信息。这就为恶意攻击制造了机会。

USB

USB是一种不对等总线,也就是有主机和客户机的区别,所有的操作都由Host发出。USB有两个比较重要的概念:地址,端点。

先说地址,Host是没有地址的,只有设备才有。类似的概念是MAC地址,局域网用普通hub大家连在一起,所有的数据包都会经过你的网卡,只有符合你的MAC的数据包网卡才会接受(注意这是最原始的情况,请网络帝指正)。

当一个新的USB设备插入host,比如优盘,由于USB接口上的电平变化,HOST控制器得知有设备插入并且区分出是1.x还是2.0(上拉下拉电阻不同),此时设备(优盘)的USB地址是0,HOST控制器和这个地址通信,并给设备指定一个新的USB地址,范围在1~~127(可以想象是DHCP过程),随后HOST控制器就用新的USB地址来访问设备了,每一个新插入的设备都会这么处理,于是你插上两个一样的优盘,它们也会得到不同的USB地址,于是系统就能区分开两个优盘了。

USB HOST控制器给设备分配了新的USB地址以后,就开始问:你是什么东西啊,你有什么功能阿如此如此,设备会用描述符(descriptor)的方式应答(descriptor格式USB规范里面有):我的VID是xx,我的PID是yy,我的名字叫zz……如此如此。

刚才说到了USB地址,这个数值USB收发器控制电路会保存下来用于今后的通信,但是因为这个东西比较特殊,所以大多数的芯片是不能手工修改自己的USB地址的。

端点是真正执行数据通信的端口,端点0是始终可以用的,被称为控制端点,具体就不细说了。

ok,上面废话这么多,下面开始说主题:PS Jailbreak。

一句话概括:PS Jailbreak通过精心构造的特殊USB描述符,使PS3处理这些描述符的时候Heap overflow,导致代码注入进而获取了GameOS的访问权限。

下面详细介绍PS Jailbreak(以下简称JB)攻击过程

(绝大多数翻译自http://ps3wiki.lan.st/index.php/PSJailbreak_Exploit_Reverse_Engineering,并加上必要的解释说明):

JB设备的外形(注意不是物理外形,是技术上的)是一个“六口 USB Hub”,注意我用了双引号,这东西只是对外宣称自己是Hub,实际上只是为了满足USB协议的需求,并没有完整地实现USB Hub的全部功能。

PS3开机的时候,在特定的情况下会在USB接口上搜索官方的JIG设备(我不知道这玩意的具体功能,操作方法是按POWER后200ms内按Eject),JB利用这个特性在开机检测JIG的时候在其虚拟的六个USB Port上轮番插拔6个设备(…………),由于系统需要为每个设备的处理过程分配内存,通过精心构造的USB描述符,实现了Heap overflow。

Port1:Hub初始化以后,第一个设备插入,pid/vid 0xAAAA/0x5555,有4个配置,每一个长度都是0xf00,由于这个长度没有超过4K的页面,所以推测PS3系统的malloc会为每一个配置分配一个4k的内存页。为什么要4个呢,因为可能已经有空闲内存了,用4个是保证有足够大的概率把页面对齐到4k边界上。然后JB重新报告其配置为18字节。其实在这个比较长的配置里面包含有payload(也就是用于注入攻击的功能代码)。

Port2:PS3读取完成1号设备的描述符以后,JB切换回Hub USB地址,然后谎称第二个设备插入,pid/vid 0xAAAA/0xBBBB,这个设备有一个22字节的描述符,只有前18个字节是有意义的,最后4个意义不明。

Port3:随后这个设备插入,pid/vid 0xAAAA/0x5555,和第一个一样但是描述符不一样,他有两个配置描述符,每一个长度为0xa4d,大部分的数据被认为是垃圾。按照对堆管理器的猜测,这些描述符会被放在一个新的4k页面上,紧随之前的两个设备。

Port2:拔出。这个设备的拔出导致一个显而易见的结果,第一个设备和第三个设备之间分配的内存被释放了。

OK,上面这样的折腾,准备好了真正的攻击环境上下文。

Port4:连接。pid/vid 0xAAAA/0x5555,有三个配置描述符。

配置描述符A,18字节的正常描述符。

配置描述符B,和A一样的描述符,但是当PS3初次读取它之后,它把自己的长度变成了0字节。这是破解的关键之处,但是其具体含义含混不清,它导致了配置描述符C后面的数据覆盖了某一个malloc的边界标志,很可能是属于Port3的。但是这个溢出的详细原因恐怕得看攻击代码本身了。

配置描述符C,这个描述符开始和A是一样的,但是最后多了14个字节。

.. .. 3e 21 00 00 00 00fa ce b0 03 aa bb cc dd80 00 00 00 00 46 50 0080 00 00 00 00 3d ee 70

前六个字节被认为是占位(但是我不这么认为,by hyperiris),接下来是一个magic number,fa ce b0 03 aa bb cc dd,用英语来看就是FACEBOOK AABBCCDD,随后的数据是一个指针,它覆盖了malloc块的边界标记,这会导致malloc在之后处理这个块的时候发生错误,使其按照攻击者的意愿在指定的位置操作内存。(这是两个64位的指针,by hyperiris)

Port5:当Port4完成工作以后,假的JIG被插入到了Port5,它和SONY官方的JIG PID/VID 0x054C/0x02EB æ˜¯ä¸€æ ·çš„ï¼ŒæŽ¨æµ‹å’Œå®˜æ–¹çš„é…ç½ ®å’Œç«¯ç‚¹ä¸€è‡´ã€‚

可以猜测由于这个玩意(JIG)是PS3已知的设备,PS3系统不会为它在堆上分配内存。

随后PS3发送64字节的数据要求JIG进行认证,然后JB返回64字节的应答。PS3将会分配内存来保存这个应答(!!!!),由于之前malloc块的边界标记已经被Port4的插入所修改,所以这次内存分配将会在一个设计好的位置,也就是某一个函数的前面,(某函数24字节偏移之前),然后函数的前面被这64字节覆盖了(!!!!)

由于系统的JIG认证代码没有被patch,所以JB返回的数据被验证无效。

Port3:拔出。JB现在通知PS3,Port3拔出,这导致PS3释放为Port3设备配置描述符分配的内存,也就是被Port4设备描述符覆盖的那个。

于是Shell code此刻被调用,R3寄存器现在指向的是Port3配置描述符的内存边界标记位置。

Shellcode:

ROM:00000018                 ld      %r4, -0x10(%r3)ROM:0000001C                 ld      %r3, -8(%r3)ROM:00000020ROM:00000020 loc_20:                               # CODE XREF: sub_18+14�jROM:00000020                 ld      %r5, 0x18(%r3)ROM:00000024                 addi    %r3, %r3, 0x1000ROM:00000028                 cmpw    %r4, %r5ROM:0000002C                 bne     loc_20ROM:00000030                 addi    %r6, %r3, -0xFE0ROM:00000034                 mtctr   %r6ROM:00000038                 bctr

R4保存的就是0xfaceb003aabbccdd,然后R3加载0x8000000000465000,然后shellcode从0x8000000000465000开始搜索每一个4k边界,直到在某一个位置发现0xFACEB003AABBCCDD,发现之后,shellcode跳转到那里,从偏移0x20处开始执行。

清理:现在一切都清静了,Port5,4,1都将被拔出。Payload应该在Port1拔出之前将自己复制到一个不会被释放的内存块里。

Port6:这个设备没有任何的实际意义/功能,vid/pid 0xAAAA/0xDEC0,只响应一个控制传输0xAA,当PS3给这个设备发送这个控制传输,JB就知道自己成功了,并点亮LED。

在原始的JB里面,payload会检测这个设备是不是被拔掉,如果拔掉了,就调用LV1_Panic宕机。PSGroove把这个傻逼功能去掉了。

至于payload代码,和PS3版本有关,具体资料没有,因为需要ps3 main memory dump。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有